package patterns.creational.prototype;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 原型模式示例
 * 用原型实例指定创建对象的种类，并且通过拷贝这些原型创建新的对象
 */
public class PrototypePattern {

    public static void main(String[] args) {
        // 浅克隆示例
        System.out.println("===== 浅克隆示例 =====");
        ShallowShape circle = new ShallowCircle(10, 10, 5);
        ShallowShape clonedCircle = circle.clone();
        
        System.out.println("原始圆形: " + circle);
        System.out.println("克隆圆形: " + clonedCircle);
        
        // 修改克隆对象的属性
        clonedCircle.move(5, 5);
        System.out.println("移动后的克隆圆形: " + clonedCircle);
        System.out.println("原始圆形保持不变: " + circle);
        
        // 深克隆示例
        System.out.println("\n===== 深克隆示例 =====");
        DeepShape rectangle = new DeepRectangle(10, 10, 20, 30);
        rectangle.addTag("原始");
        rectangle.addTag("矩形");
        
        DeepShape clonedRectangle = rectangle.clone();
        
        System.out.println("原始矩形: " + rectangle);
        System.out.println("克隆矩形: " + clonedRectangle);
        
        // 修改克隆对象的引用类型属性
        clonedRectangle.addTag("克隆");
        System.out.println("添加标签后的克隆矩形: " + clonedRectangle);
        System.out.println("原始矩形的标签保持不变: " + rectangle);
        
        // 原型注册表示例
        System.out.println("\n===== 原型注册表示例 =====");
        ShapeRegistry registry = new ShapeRegistry();
        
        // 注册原型
        registry.addShape("小圆", new Circle(0, 0, 5));
        registry.addShape("大圆", new Circle(0, 0, 10));
        registry.addShape("小矩形", new Rectangle(0, 0, 10, 20));
        registry.addShape("大矩形", new Rectangle(0, 0, 20, 30));
        
        // 从注册表中克隆对象
        Shape smallCircle = registry.getShape("小圆");
        smallCircle.move(5, 5);
        System.out.println("从注册表克隆的小圆: " + smallCircle);
        
        Shape largeRectangle = registry.getShape("大矩形");
        largeRectangle.move(15, 15);
        System.out.println("从注册表克隆的大矩形: " + largeRectangle);
    }
}

/**
 * 浅克隆示例
 */
abstract class ShallowShape implements Cloneable {
    private int x;
    private int y;
    
    public ShallowShape(int x, int y) {
        this.x = x;
        this.y = y;
    }
    
    public void move(int dx, int dy) {
        this.x += dx;
        this.y += dy;
    }
    
    public int getX() {
        return x;
    }
    
    public int getY() {
        return y;
    }
    
    @Override
    public ShallowShape clone() {
        try {
            // Object.clone()方法执行浅克隆
            return (ShallowShape) super.clone();
        } catch (CloneNotSupportedException e) {
            // 这不应该发生，因为我们实现了Cloneable接口
            throw new RuntimeException(e);
        }
    }
}

class ShallowCircle extends ShallowShape {
    private int radius;
    
    public ShallowCircle(int x, int y, int radius) {
        super(x, y);
        this.radius = radius;
    }
    
    public int getRadius() {
        return radius;
    }
    
    @Override
    public String toString() {
        return "Circle{" +
                "x=" + getX() +
                ", y=" + getY() +
                ", radius=" + radius +
                '}';
    }
}

/**
 * 深克隆示例
 */
abstract class DeepShape implements Cloneable {
    private int x;
    private int y;
    private List<String> tags = new ArrayList<>();
    
    public DeepShape(int x, int y) {
        this.x = x;
        this.y = y;
    }
    
    public void move(int dx, int dy) {
        this.x += dx;
        this.y += dy;
    }
    
    public int getX() {
        return x;
    }
    
    public int getY() {
        return y;
    }
    
    public void addTag(String tag) {
        tags.add(tag);
    }
    
    public List<String> getTags() {
        return tags;
    }
    
    @Override
    public DeepShape clone() {
        try {
            // 首先执行浅克隆
            DeepShape cloned = (DeepShape) super.clone();
            
            // 然后手动克隆可变对象
            cloned.tags = new ArrayList<>(this.tags);
            
            return cloned;
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }
}

class DeepRectangle extends DeepShape {
    private int width;
    private int height;
    
    public DeepRectangle(int x, int y, int width, int height) {
        super(x, y);
        this.width = width;
        this.height = height;
    }
    
    public int getWidth() {
        return width;
    }
    
    public int getHeight() {
        return height;
    }
    
    @Override
    public String toString() {
        return "Rectangle{" +
                "x=" + getX() +
                ", y=" + getY() +
                ", width=" + width +
                ", height=" + height +
                ", tags=" + getTags() +
                '}';
    }
}

/**
 * 原型注册表示例
 */
interface Shape extends Cloneable {
    Shape clone();
    void move(int dx, int dy);
}

class Circle implements Shape {
    private int x;
    private int y;
    private int radius;
    
    public Circle(int x, int y, int radius) {
        this.x = x;
        this.y = y;
        this.radius = radius;
    }
    
    @Override
    public void move(int dx, int dy) {
        this.x += dx;
        this.y += dy;
    }
    
    @Override
    public Shape clone() {
        try {
            return (Shape) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }
    
    @Override
    public String toString() {
        return "Circle{" +
                "x=" + x +
                ", y=" + y +
                ", radius=" + radius +
                '}';
    }
}

class Rectangle implements Shape {
    private int x;
    private int y;
    private int width;
    private int height;
    
    public Rectangle(int x, int y, int width, int height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }
    
    @Override
    public void move(int dx, int dy) {
        this.x += dx;
        this.y += dy;
    }
    
    @Override
    public Shape clone() {
        try {
            return (Shape) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }
    
    @Override
    public String toString() {
        return "Rectangle{" +
                "x=" + x +
                ", y=" + y +
                ", width=" + width +
                ", height=" + height +
                '}';
    }
}

// 原型注册表
class ShapeRegistry {
    private Map<String, Shape> shapes = new HashMap<>();
    
    public void addShape(String key, Shape shape) {
        shapes.put(key, shape);
    }
    
    public Shape getShape(String key) {
        Shape shape = shapes.get(key);
        if (shape != null) {
            // 返回克隆对象，而不是原型本身
            return shape.clone();
        }
        return null;
    }
} 